#include "Object.h"


//This should never be called
Object::Object(){
	type = null;
}
Object::Object(int locx, int locy, int locz,vector<vector<vector<Floor*>>> floor)
{
	condition = FINE;
	collision = false;
	dir = NODIR;
	theFloor = floor;
	x = locx;
	y = locy;
	z = locz;
	type = null;
	removeable = false;
}

Object::~Object(void)
{
}


//
//Getters
//


ObjectType Object::getType(){return type;}

Condition Object::getCondition(){return condition;}

int Object::getX(){return x;}

int Object::getY(){return y;}

int Object::getZ(){return z;}

Direction Object::getDirection(){return dir;}

bool Object::isCollide(){return collision;}

bool Object::needsRemoval(){return removeable;}

//
//Setters
//

void Object::changeDirection(Direction direction){dir = direction;}

void Object::setCollide(bool set){collision = set;}

//
//Virtual Methods
//

void Object::doTimeStep(Object *Tait)
{
}
//When an this object is hit by the collider do certain stuff
void Object::collide(Object* collider)
{
	collision = false;

}
//When an this object hits into another object
void Object::collideWith(Object* collidee){
	collision = false;
}

void Object::buttonPress() //For levers
{
}


//Makes sure there is a legal move to make before moving
void Object::move(Direction direction)
{
	//checks direction and if its in bounds and if there is a collision, if its ok to move, then move, otherwise
	//with collision put up a collision flag for game to handle
	dir = direction;
	switch(direction){
		case UP:	
			if(legalFloor()||theFloor[x][y][z]->getType() == SNORTH){
				if(theFloor[x][y][z]->getType() != SNORTH){
					if(!checkCollide()){					
						theFloor[x][y][z]->walkOffEvent();
						theFloor[x][y][z]->changeObject(NONE);
						theFloor[x][y-1][z]->changeObject(type);
						theFloor[x][y-1][z]->walkOnEvent();
						y-=1;}
					else 
						collision = true;
				}
				else{
					z+=1;						
					if(!checkCollide()){
						theFloor[x][y][z-1]->walkOffEvent();
						theFloor[x][y][z-1]->changeObject(NONE);
						theFloor[x][y-1][z]->changeObject(type);
						theFloor[x][y-1][z]->walkOnEvent();
						y-=1;							
					}
					else{collision = true;}				
				}
			}
			break;
		case DOWN:	
			if(legalFloor()||theFloor[x][y][z]->getType() == SSOUTH){
				if(theFloor[x][y][z]->getType() != SSOUTH){
					if(!checkCollide()){					
						theFloor[x][y][z]->walkOffEvent();
						theFloor[x][y][z]->changeObject(NONE);
						theFloor[x][y+1][z]->changeObject(type);
						theFloor[x][y+1][z]->walkOnEvent();
						y+=1;}
					else 
						collision = true;
				}
				else{
					z+=1;						
					if(!checkCollide()){
						theFloor[x][y][z-1]->walkOffEvent();
						theFloor[x][y][z-1]->changeObject(NONE);
						theFloor[x][y+1][z]->changeObject(type);
						theFloor[x][y+1][z]->walkOnEvent();
						y+=1;							
					}
					else{collision = true;}			
				}
			}
			break;
		case RIGHT:	
			if(legalFloor()||theFloor[x][y][z]->getType() == SEAST){
				if(theFloor[x][y][z]->getType() != SEAST){
					if(!checkCollide()){					
						theFloor[x][y][z]->walkOffEvent();
						theFloor[x][y][z]->changeObject(NONE);
						theFloor[x+1][y][z]->changeObject(type);
						theFloor[x+1][y][z]->walkOnEvent();
						x+=1;}
					else 
						collision = true;
				}
				else{
					z+=1;						
					if(!checkCollide()){
						theFloor[x][y][z-1]->walkOffEvent();
						theFloor[x][y][z-1]->changeObject(NONE);
						theFloor[x+1][y][z]->changeObject(type);
						theFloor[x+1][y][z]->walkOnEvent();
						x+=1;							
					}
					else{collision = true;}			
				}
			}
			break;
		case LEFT:	
			if(legalFloor()||theFloor[x][y][z]->getType() == SWEST){
				if(theFloor[x][y][z]->getType() != SWEST){
					if(!checkCollide()){					
						theFloor[x][y][z]->walkOffEvent();
						theFloor[x][y][z]->changeObject(NONE);
						theFloor[x-1][y][z]->changeObject(type);
						theFloor[x-1][y][z]->walkOnEvent();
						x-=1;}
					else 
						collision = true;
				}
				else{
					z+=1;						
					if(!checkCollide()){
						theFloor[x][y][z-1]->walkOffEvent();
						theFloor[x][y][z-1]->changeObject(NONE);
						theFloor[x-1][y][z]->changeObject(type);
						theFloor[x-1][y][z]->walkOnEvent();
						x-=1;							
					}
					else{collision = true;}			
				}
			}
			break;
	}

}


//Attempts to Apply Gravity to an object
void Object::applyGravity(Equip currentEquip)
{
	if(z>0 && theFloor[x][y][z]->getType() == EMPTY){
		if(theFloor[x][y][z-1]->getObjectType()!= BLOCK&&theFloor[x][y][z-1]->getObjectType()!= IMOBLOCK){
			theFloor[x][y][z]->walkOffEvent();
			theFloor[x][y][z]->changeObject(NONE);
			theFloor[x][y][z-1]->changeObject(type);								
			theFloor[x][y][z-1]->walkOnEvent();
			z-=1;
			applyGravity(currentEquip);
		}
	}
}

void Object::react(Equip currentEquip)
{
}
//
//Helper Methods(public ones)
//

//Helper method to determine if moving a direction is in vector bounds
bool Object::bounds(){
	switch(dir){
		case UP:	
			return getY()>0;
			break;
		case DOWN:	
			return getY()<(int)theFloor[x].size()-1;
			break;
		case RIGHT:	
			return getX()<(int)theFloor.size()-1;
			break;
		case LEFT:	
			return getX()>0;
			break;
	}

	return true;
}


//
//Helper to see if a spots free
//
bool Object::isLegal(Direction dirx){
		FloorType nextFloor;
		FloorState floorState;
		FloorType currentFloor = theFloor[x][y][z]->getType();
		if(bounds()){
			switch(dirx){
		case UP:	
			nextFloor = theFloor[x][y-1][z]->getType();
			floorState = theFloor[x][y-1][z]->getFloorState();
			return  !(nextFloor == WSOUTH) && !(currentFloor == WNORTH) &&!(floorState == BLOCKCREATED) 
				&& !(nextFloor == GRAVEL) && !(nextFloor == WATER) && !(nextFloor==EMPTY);
			break;
		case DOWN:	
			nextFloor = theFloor[x][y+1][z]->getType();
			floorState = theFloor[x][y+1][z]->getFloorState();
			return  !(nextFloor == WNORTH)&& !(currentFloor == WSOUTH)&&!(floorState == BLOCKCREATED)
				&& !(nextFloor == GRAVEL) && !(nextFloor == WATER)&& !(nextFloor==EMPTY);
			break;
		case RIGHT:	
			nextFloor = theFloor[x+1][y][z]->getType();
			floorState = theFloor[x+1][y][z]->getFloorState();
			return  !(nextFloor == WWEST)&& !(currentFloor == WEAST)&&!(floorState == BLOCKCREATED)
				&& !(nextFloor == GRAVEL) && !(nextFloor == WATER)&& !(nextFloor==EMPTY);
			break;
		case LEFT:	
			nextFloor = theFloor[x-1][y][z]->getType();
			floorState = theFloor[x-1][y][z]->getFloorState();
			return  !(nextFloor == WEAST)&& !(currentFloor == WWEST)&&!(floorState == BLOCKCREATED)
				&& !(nextFloor == GRAVEL) && !(nextFloor == WATER) && !(nextFloor==EMPTY);
			break;

			}
		}
		return false;

}

//This is method that will need redefinition for every object
//Checks if the direction that you're going is legal
bool Object::legalFloor(){
	FloorType nextFloor;
	FloorState floorState;
	FloorType currentFloor = theFloor[x][y][z]->getType();
	if(bounds()){
		switch(dir){
		case UP:	
			nextFloor = theFloor[x][y-1][z]->getType();
			floorState = theFloor[x][y-1][z]->getFloorState();
			return  !(nextFloor == WSOUTH) && !(currentFloor == WNORTH) &&!(floorState == BLOCKCREATED);
			break;
		case DOWN:	
			nextFloor = theFloor[x][y+1][z]->getType();
			floorState = theFloor[x][y+1][z]->getFloorState();
			return  !(nextFloor == WNORTH)&& !(currentFloor == WSOUTH)&&!(floorState == BLOCKCREATED);
			break;
		case RIGHT:	
			nextFloor = theFloor[x+1][y][z]->getType();
			floorState = theFloor[x+1][y][z]->getFloorState();
			return  !(nextFloor == WWEST)&& !(currentFloor == WEAST)&&!(floorState == BLOCKCREATED);
			break;
		case LEFT:	
			nextFloor = theFloor[x-1][y][z]->getType();
			floorState = theFloor[x-1][y][z]->getFloorState();
			return  !(nextFloor == WEAST)&& !(currentFloor == WWEST)&&!(floorState == BLOCKCREATED);
			break;

		}
	}
	return false;
}

//
//Private Helper Method
//


//helper to see if theres a collision
bool Object::checkCollide(){

	if(bounds()){
		switch(dir){
		case UP:				
			return theFloor[x][y-1][z]->getObjectType() != NONE;
			break;
		case DOWN:	
			return theFloor[x][y+1][z]->getObjectType() != NONE;
			break;
		case RIGHT:	
			return theFloor[x+1][y][z]->getObjectType() != NONE;
			break;
		case LEFT:	
			return theFloor[x-1][y][z]->getObjectType() != NONE;
			break;
		}
	}
	return false;
}


//helper to see if theres a collision
bool Object::checkCollide(Direction dir2){

	if(bounds()){
		switch(dir2){
		case UP:				
			return theFloor[x][y-1][z]->getObjectType() != NONE;
			break;
		case DOWN:	
			return theFloor[x][y+1][z]->getObjectType() != NONE;
			break;
		case RIGHT:	
			return theFloor[x+1][y][z]->getObjectType() != NONE;
			break;
		case LEFT:	
			return theFloor[x-1][y][z]->getObjectType() != NONE;
			break;
		}
	}
	return false;
}


void Object::doFloor(Equip currentEquip){

	condition = FINE;
	//sliding will set you into sliding unless you're against a wall
	if(theFloor[x][y][z] ->getType() == ICE){
		if(!checkCollide()&&bounds()){
			condition = SLIDING;
			move(dir);
		}
	}



}


